package com.snowruin.redis.lock.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import com.snowruin.distributed.lock.common.DistributedLock;
import com.snowruin.distributed.lock.common.utils.SPELUtils;
import com.snowruin.redis.lock.annotation.RedisLockAction;
import com.snowruin.redis.lock.autoconfigure.RedisDistributedLockAutoConfiguration;
import com.snowruin.redis.lock.enums.FailHandler;

/**
 * RedisLockAction 的  切面
 * @author zxm
 * @version 1.0.0
 * @date 2019-03-04 10:30:00
 * @url https://www.snowruin.com
 *
 */

@Aspect
@Configuration
@ConditionalOnClass(DistributedLock.class)
@AutoConfigureAfter(RedisDistributedLockAutoConfiguration.class)
public class RedisDistributedLockAspectConfiguration {
	
	@Autowired
	private DistributedLock distributedLock;

	/**
	 * 环绕增强
	 * @param joinPoint
	 * @return
	 */
	@Around("@annotation(com.snowruin.redis.lock.annotation.RedisLockAction)")
	public Object around(ProceedingJoinPoint joinPoint) {
		
		Signature signature = joinPoint.getSignature();
		
		Method method = ((MethodSignature) signature).getMethod();
		
		RedisLockAction annotation = method.getAnnotation(RedisLockAction.class);
		
		String keyName = annotation.value();
		
		Object[] args = joinPoint.getArgs();
		
		keyName = SPELUtils.parser(keyName, method, args);
		
		// 重试次数
		int retryCount =  annotation.handler().equals(FailHandler.CONTINUE) ? annotation.retryCount() : 0;
	
		boolean lock = distributedLock.lock(keyName,annotation.keepMillis(),retryCount,annotation.sleepMillis());
		
		if(!lock) {
			LoggerFactory.getLogger(this.getClass()).info("获取锁失败，key 名称为： {}",keyName);
			return null;
		}
		
		LoggerFactory.getLogger(this.getClass()) .info("获取锁成功，key 名称为 ： {}",keyName);
		
		try {
			return joinPoint.proceed();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			boolean releaseLock = distributedLock.releaseLock(keyName);
			if(!releaseLock) {
				LoggerFactory.getLogger(this.getClass()).info("释放锁成功,key 名称为 ： {}",keyName);
			}else {
				LoggerFactory.getLogger(this.getClass()).info("释放锁失败, key 名称为： {}",keyName);
			}
		}
		return null;
	}
}
